#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <ctime>
#include <atomic>
#include <fstream>
#include <vector>
#include <boost/algorithm/string.hpp>

using std::string;

namespace ns_util
{
    const string temp_path = "./temp/";
    class PathUtil
    {
    public:
        // 拼接
        static string AddSuffix(const string &file_name, const string &suffix)
        {
            string file_path = temp_path;
            file_path += file_name;
            file_path += suffix;
            return file_path;
        }
        // 构建源文件路径+后缀
        static string Src(const string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }
        // 构建执行文件路径+后缀
        static string Exe(const string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }
        // 构建编译错误文件路径+后缀
        static string ComplieError(const string &file_name)
        {
            return AddSuffix(file_name, ".complie_error");
        }
        // 构建标准输入文件路径+后缀
        static string Stdin(const string &file_name)
        {
            return AddSuffix(file_name, ".stdin");
        }
        // 构建标准输出文件路径+后缀
        static string Stdout(const string &file_name)
        {
            return AddSuffix(file_name, ".stdout");
        }
        // 构建标准错误文件路径+后缀
        static string Stderr(const string &file_name)
        {
            return AddSuffix(file_name, ".stderr");
        }
    };
    class TimeUtil
    {
    public:
        // 获取时间戳(yyyy-mm-dd hh:mm:ss)
        static string GetTimeStamp()
        {
            struct timeval _time;
            struct tm _ltm;

            gettimeofday(&_time, nullptr);
            _ltm = *localtime(&_time.tv_sec);
            string datetime = std::to_string(_ltm.tm_year + 1900);
            datetime += "-";
            datetime += (_ltm.tm_mon + 1 < 10 ? "0" : "") + std::to_string(_ltm.tm_mon + 1);
            datetime += "-";
            datetime += (_ltm.tm_mday + 1 < 10 ? "0" : "") + std::to_string(_ltm.tm_mday);
            datetime += " ";
            datetime += (_ltm.tm_hour + 1 < 10 ? "0" : "") + std::to_string(_ltm.tm_hour);
            datetime += ":";
            datetime += (_ltm.tm_min + 1 < 10 ? "0" : "") + std::to_string(_ltm.tm_min);
            datetime += ":";
            datetime += (_ltm.tm_sec + 1 < 10 ? "0" : "") + std::to_string(_ltm.tm_sec);
            return datetime;
        }
        // 获取毫秒时间戳
        static string GetTimeMs()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            return std::to_string(_time.tv_sec * 1000 + _time.tv_usec / 1000);
        }
    };
    class FileUtil
    {
    public:
        // 判断文件存在
        static bool IsFileExists(const string &file_path)
        {
            struct stat st;
            if (stat(file_path.c_str(), &st) == 0)
            {
                // 成功
                return true;
            }
            return false;
        }
        // 生成唯一文件名
        static string UniqFileName()
        {
            static std::atomic_uint id(0);
            id++;
            // 毫秒级时间戳+原子性递增唯一值：保证唯一文件名
            string ms = TimeUtil::GetTimeMs();
            string uid = std::to_string(id);
            return ms + "_" + uid;
        }
        // 写入文件
        static bool WriteFile(const string &target, const string &content)
        {
            std::ofstream out(target);
            if (!out.is_open())
            {
                return false;
            }
            out.write(content.c_str(), content.size());
            out.close();
            return true;
        }
        // 读取文件
        static bool ReadFile(const string &target, string *content, bool keep_endl = false)
        {
            content->clear();

            std::ifstream in(target);
            if (!in.is_open())
            {
                return false;
            }

            string line;
            while (getline(in, line))
            {
                (*content) += line;
                (*content) += (keep_endl ? "\n" : "");
            }
            in.close();
            return true;
        }
    };
    class StringUtil
    {
    public:
        /**************
         * target:切分后的子串
         * str:需要切割的字符串
         * sep:分割符
         * ************* */
        static void SplitString(std::vector<string> *target, const string &str, const string &sep)
        {
            boost::split(*target, str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }
    };
}